#version 330 core
out vec4 FragColor;

in VS_OUT {
  vec3 FragPos;
  vec3 Normal;
  vec2 TexCoords;
  vec4 FragPosLightSpace;
} fs_in;

uniform sampler2D diffuseTexture;
uniform sampler2D shadowMap;

uniform vec3 lightPos;
uniform vec3 viewPos;

float ShadowCalculation(vec4 fragPosLightSpace) {
  // perform perspective divide
  vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
  if (projCoords.z > 1.0) {
	return 0.0;
  }
  projCoords = projCoords * 0.5 + 0.5; // linear mapping [-1,1] -> [0, 1]
  float closestDepth = texture(shadowMap, projCoords.xy).r;
  float currentDepth = projCoords.z;
  // Check whether current frag pos is in shadow
  float bias = 0.005;
  float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
  return shadow;
}

void main() {
  vec3	color	   = texture(diffuseTexture, fs_in.TexCoords).rgb;
  vec3	normal	   = normalize(fs_in.Normal);
  vec3	lightColor = vec3(1.0);
  // Ambient
  vec3	ambient	   = 0.15 * color;
  // Diffuse
  vec3	lightDir   = normalize(lightPos - fs_in.FragPos);
  float diff	   = max(dot(lightDir, normal), 0.0);
  vec3	diffuse	   = diff * lightColor;
  // Specular
  vec3	viewDir	   = normalize(viewPos - fs_in.FragPos);
  float spec	   = 0.0;
  vec3	halfwayDir = normalize(lightDir + viewDir);
  spec			   = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
  vec3	specular   = spec * lightColor;
  // Calculate shadow
  float shadow	   = ShadowCalculation(fs_in.FragPosLightSpace);
  vec3	lighting   = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;

  FragColor = vec4(lighting, 1.0f);
}

